package com.google.android.catalog.app.compose.sample

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.absolutePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.unit.dp
import com.gitee.wsl.compose.chart.ChartLayout
import com.gitee.wsl.compose.chart.ExperimentalKoalaPlotApi

import com.gitee.wsl.compose.chart.generateHueColorPalette
import com.gitee.wsl.compose.chart.legend.Flow
import com.gitee.wsl.compose.chart.legend.Legend
import com.gitee.wsl.compose.chart.legend.LegendLocation
import com.gitee.wsl.compose.chart.xy.XYGraph
import com.gitee.wsl.compose.chart.xy.axis.model.CategoryAxisModel
import com.gitee.wsl.compose.chart.xy.axis.model.FloatLinearAxisModel
import com.gitee.wsl.compose.chart.xy.bar.DefaultVerticalBar
import com.gitee.wsl.compose.chart.xy.bar.group.GroupedVerticalBarPlot
import com.gitee.wsl.compose.chart.xy.bar.group.model.VerticalBarPlotGroupedPointEntry
import com.gitee.wsl.compose.chart.xy.bar.model.DefaultVerticalBarPosition

import com.gitee.wsl.compose.chart.xy.bar.model.VerticalBarPosition
import com.gitee.wsl.compose.modifier.layout.VerticalRotation
import com.gitee.wsl.compose.modifier.layout.rotateVertically
import com.gitee.wsl.compose.ui.widget.Symbol
import com.gitee.wsl.compose.modifier.layout
import com.gitee.wsl.ext.number.toString

import kotlin.math.ceil

private val colors = generateHueColorPalette(PopulationData.Categories.entries.size)

private fun barChartEntries(): List<VerticalBarPlotGroupedPointEntry<Int, Float>> {
    return PopulationData.years.mapIndexed { yearIndex, year ->
        object : VerticalBarPlotGroupedPointEntry<Int, Float> {
            override val x: Int = year

            override val y: List<VerticalBarPosition<Float>> = object : AbstractList<VerticalBarPosition<Float>>() {
                override val size: Int
                    get() = PopulationData.Categories.entries.size

                override fun get(index: Int): VerticalBarPosition<Float> {
                    return DefaultVerticalBarPosition(
                        0f,
                        PopulationData.data[PopulationData.Categories.entries[index]]!![yearIndex].toFloat()
                    )
                }
            }
        }
    }
}

@OptIn(ExperimentalKoalaPlotApi::class)
@Composable
private fun LegendView(thumbnail: Boolean = false) {
    if (!thumbnail) {
        Legend.Flow(
            itemCount = PopulationData.Categories.entries.size,
            symbol = { i ->
                Symbol(modifier = Modifier.size(padding), fillBrush = SolidColor(colors[i]))
            },
            label = { i ->
                Text(PopulationData.Categories.entries[i].toString())
            },
        )
    }
}

@OptIn(ExperimentalKoalaPlotApi::class)
val groupedVerticalBarSampleView = object : SampleView {
    override val name: String = "Grouped Vertical Bar"

    override val thumbnail = @Composable {
        ThumbnailTheme {
            BarSample2Plot(true, name)
        }
    }

    override val content: @Composable () -> Unit = @Composable {
        Column {
            ChartLayout(
                modifier = Modifier.sizeIn(minHeight = 200.dp, maxHeight = 600.dp).weight(1f)
            ) {
                BarSample2Plot(false, "New York City Population")
            }
        }
    }
}

private const val PopulationScale = 1E6f

@OptIn(ExperimentalKoalaPlotApi::class)
@Composable
private fun BarSample2Plot(thumbnail: Boolean, title: String) {
    val barChartEntries: List<VerticalBarPlotGroupedPointEntry<Int, Float>> = remember(thumbnail) { barChartEntries() }

    ChartLayout(
        modifier = paddingMod,
        title = { ChartTitle(title) },
        legend = { LegendView(thumbnail) },
        legendLocation = LegendLocation.BOTTOM
    ) {
        XYGraph(
            xAxisModel = CategoryAxisModel(PopulationData.years),
            yAxisModel = FloatLinearAxisModel(
                0f..(ceil(PopulationData.maxPopulation / PopulationScale) * PopulationScale),
                minorTickCount = 0
            ),
            content = {
                GroupedVerticalBarPlot(
                    data = barChartEntries,
                    bar = { dataIndex, groupIndex, _ ->
                        DefaultVerticalBar(
                            brush = SolidColor(colors[groupIndex]),
                            modifier = Modifier.sizeIn(minWidth = 5.dp, maxWidth = 20.dp),
                        ) {
                            if (!thumbnail) {
                                val borough = PopulationData.Categories.entries[groupIndex]
                                val pop = PopulationData.data[borough]!![dataIndex]
                                HoverSurface { Text("$borough: $pop") }
                            }
                        }
                    }
                )
            },
            xAxisLabels = {
                if (!thumbnail) AxisLabel("$it", Modifier.padding(top = 2.dp))
            },
            xAxisTitle = {
                if (!thumbnail) AxisTitle("Year")
            },
            yAxisLabels = {
                if (!thumbnail) {
                    AxisLabel(
                        (it / PopulationScale).toString(2),
                        Modifier.absolutePadding(right = 2.dp)
                    )
                }
            },
            yAxisTitle = {
                if (!thumbnail) {
                    Text(
                        "Population (Millions)",
                        color = MaterialTheme.colorScheme.onBackground,
                        style = MaterialTheme.typography.titleMedium,
                        modifier = Modifier
                            .layout {
                                rotateVertically(VerticalRotation.COUNTER_CLOCKWISE)
                            }
                            .padding(bottom = padding),
                    )
                }
            },
            verticalMajorGridLineStyle = null
        )
    }
}
